// -------------------------
// Author:  fatmonsterz
// Purpose: Handle variables [also with simple callbacks!]
// -------------------------
#include "ConfigManager.h"
#include "DebugConsole.h"

#include <libconfig.hh>
using namespace libconfig;

// -------------------------
// _type -------------------
// -------------------------
enum VARTYPE
{
	VAR_BASE,
	VAR_BOOL,
	VAR_INT,
	VAR_FLOAT,
	VAR_STRING
};

// -------------------------
// IntVar ------------------
// -------------------------
IntVar::IntVar(const std::string& name, int val = 0, int min = 0, int max = 1) : VarBase(name)
{
	_type = VAR_INT;

	_default = val;
	_val = _default;
	_min = min;
	_max = max;
}

void IntVar::setValue(int v)
{
	_val = v;

	if(_val > _max)
		_val = _max;
	if(_val < _min)
		_val = _min;

	if(this->_ChangeCallback != NULL)
		this->_ChangeCallback();
}

int IntVar::getValue()
{
	return _val;
}

// -------------------------
// BoolVar -----------------
// -------------------------
BoolVar::BoolVar(const std::string& name, bool dft) : VarBase(name)
{
	_type = VAR_BOOL;

	_default = dft;
	_val = _default;
}

void BoolVar::setValue(bool v)
{
	_val = v;

	if(this->_ChangeCallback != NULL)
		this->_ChangeCallback();
}

bool BoolVar::getValue()
{
	return _val;
}

// -------------------------
// FloatVar ----------------
// -------------------------
FloatVar::FloatVar(const std::string& name, float dft, float min, float max) : VarBase(name)
{
	_type = VAR_FLOAT;

	_default = dft;
	_val = _default;
	_min = min;
	_max = max;
}

void FloatVar::setValue(float v)
{
	_val = v;

	if(_val > _max)
		_val = _max;
	if(_val < _min)
		_val = _min;

	if(this->_ChangeCallback != NULL)
		this->_ChangeCallback();
}

float FloatVar::getValue()
{
	return _val;
}

// -------------------------
// StringVar ---------------
// -------------------------
StringVar::StringVar(const std::string& name, const std::string& dft) : VarBase(name)
{
	_type = VAR_STRING;

	_default = dft;
	_strval = _default;
}

void StringVar::setValue(const std::string& v)
{
	_strval = v;

	if(this->_ChangeCallback != NULL)
		this->_ChangeCallback();
}

const std::string& StringVar::getValue()
{
	return _strval;
}

// -------------------------
// VarManager --------------
// -------------------------
VarManager::VarManager(const std::string& workDir) : m_vars()
{
	m_workDir = workDir;

	IntVar* screen_width = new IntVar("screen.width", 640, 640, 1920);
	Register(screen_width);

	IntVar* screen_height = new IntVar("screen.height", 480, 480, 1080);
	Register(screen_height);

	IntVar* screen_bpp = new IntVar("screen.bpp", 32, 32, 32);
	Register(screen_bpp);

	BoolVar* screen_fullscreen = new BoolVar("screen.fullscreen", false);
	Register(screen_fullscreen);

	BoolVar* graphics_vsync = new BoolVar("graphics.vsync", false);
	Register(graphics_vsync);

	IntVar* graphics_fpslimit = new IntVar("graphics.fpslimit", 0, 0, 10000);
	Register(graphics_fpslimit);
}

VarManager::~VarManager()
{
	m_vars.clear();
}

VarBase* VarManager::Get(const std::string& name)
{
	if(m_vars.find(name) != m_vars.end())
		return m_vars[name];
	else
		return NULL;
}

void VarManager::Register(VarBase* var)
{
	for( std::map<std::string, VarBase*>::const_iterator it = m_vars.begin(); it != m_vars.end(); ++it)
	{
		if(var->getName() == it->first)
		{
			// Already registered
			return;
		}
	}

	ConsolePrint("Registering var %s [type=%i]\n", var->getName().c_str(), var->_type);

	m_vars[var->getName()] = var;

	bool _loadedFine = false;
	try
	{
		Config cfg;
		cfg.readFile(std::string(m_workDir + "config.cfg").c_str());

		if(var->_type == VAR_BOOL)
		{
			BoolVar* bv = reinterpret_cast<BoolVar*>(var);
			bool blv;
			_loadedFine = cfg.lookupValue(var->getName(), blv);
			bv->setValue(blv);
		}
		else if(var->_type == VAR_INT)
		{
			IntVar* iv = reinterpret_cast<IntVar*>(var);
			int ilv;
			_loadedFine = cfg.lookupValue(var->getName(), ilv);
			iv->setValue(ilv);
		}
		else if(var->_type == VAR_FLOAT)
		{
			FloatVar* fv = reinterpret_cast<FloatVar*>(var);
			float flv;
			_loadedFine = cfg.lookupValue(var->getName(), flv);
			fv->setValue(flv);
		}
		else if(var->_type == VAR_STRING)
		{
			StringVar* sv = reinterpret_cast<StringVar*>(var);
			std::string slv;
			_loadedFine = cfg.lookupValue(var->getName(), slv);
			sv->setValue(slv);
		}
	}
	catch(...)
	{
		ConsolePrint("Failed to load config.cfg\n");
	}

	if(_loadedFine == false)
		ConsolePrint("Failed to load config.cfg value for variable \"%s\", using default value\n", var->getName().c_str());
}